/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
// #include "semaphore.h"
#include "transmission.h"

#include "session.h"
#include "client_trans_session_service.h"
#include "softbus_common.h"
#include "softbus_bus_center.h"
#include "utils_log.h"
#include "port_manager.h"

// static sem_t g_sessionSem;
const char *jh_sessionName1 = "khthingaccessmanager_peripherals";
const char *jh_sessionName2 = "khthingaccessmanager_peripherals";


#define MAC_SIZE 6

#define MAX_FOUND_DEVICE_NUM 32

#define MAC_STR "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_ADDR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]

static IKHSessionCallback *g_callback = NULL;

static int OnSessionOpened(int sessionId, int result)
{
    printf("\n>>>OnSessionOpened sessionId = %d, result = %d.\n", sessionId, result);
    if(result != 0){
        printf(">>>OnSessionOpened failed !!!!!!!!!!!!! \n");
    }
    return 0;
}

static void OnSessionClosed(int sessionId)
{
    printf("\n>>>OnSessionClosed sessionId = %d.\n", sessionId);
}

static void OnBytesReceived(int sessionId, const void *data, unsigned int dataLen)
{
    if (g_callback != NULL && g_callback->OnBytesReceived != NULL) {
        g_callback->OnBytesReceived(sessionId, data, dataLen);
    }
    printf(">>>***** OnBytesReceived sessionId = %d, data = %s. *****\n", sessionId, (char *)data);
    SendPortMsgInfo *recv = (SendPortMsgInfo *)data; // 使用C语言的类型转换
    printf(">>>***** ReportBytesReceived recv bundleName : %s, SN : %s, networkId : %s, type = %d, port = %d, portOffset = %d, data : %s\n",
           recv->bundleName, recv->SN, recv->networkId, recv->type, recv->port, recv->portOffset, recv->data);
           
}

static void OnMessageReceived(int sessionId, const void *data, unsigned int dataLen)
{
    if (g_callback != NULL &&  g_callback->OnMessageReceived != NULL) {
        g_callback->OnMessageReceived(sessionId, data, dataLen);
    }
    printf(" >>>OnMessageReceived sessionId = %d, data = %s\n", sessionId, (char *)data);


}

int BirefOpenSession(const char *networkId, SessionType type)
{
    SessionAttribute attr;
    (void)memset_s(&attr, sizeof(attr), 0, sizeof(attr));
    attr.linkTypeNum = LINK_TYPE_MAX;
    attr.dataType = type;
    LinkType linkTypeList[LINK_TYPE_MAX] = {
        LINK_TYPE_WIFI_WLAN_5G,
        LINK_TYPE_WIFI_WLAN_2G,
        LINK_TYPE_WIFI_P2P,
        LINK_TYPE_BR,
    };
    (void)memcpy_s(attr.linkType, sizeof(attr.linkType), linkTypeList, sizeof(linkTypeList));
    int sessionId = OpenSessionSync(jh_sessionName1, jh_sessionName2, networkId, "", &attr);
    if (sessionId < 0) {
        printf("OpenSession failed ret:%d.\n",  sessionId);
        // LOG_TO_FILE("OpenSession failed ret:%d",  sessionId);
    }
    return sessionId;
}

static ISessionListener listener = {
    .OnSessionOpened = OnSessionOpened,
    .OnSessionClosed = OnSessionClosed,
    .OnBytesReceived = OnBytesReceived,
    .OnMessageReceived = OnMessageReceived,
    .OnQosEvent = NULL
};

int BirefCreateSessionServer(void)
{
    int ret = CreateSessionServer(PKG_NAME, jh_sessionName1, &listener);
    if (ret != 0) {
        printf("CreateSessionServer fail, ret = %d.\n", ret);
        LOG_TO_FILE("CreateSessionServer fail, ret = %d", ret);
    }
    return ret;
}

int BirefRemoveSessionServer(void)
{
    int ret = RemoveSessionServer(PKG_NAME, jh_sessionName1);
    if (ret != 0) {
        printf("RemoveSessionServer fail, ret = %d.\n", ret);
        LOG_TO_FILE("RemoveSessionServer fail, ret = %d", ret);
    }
    return ret;
}

int BirefSendMessage(const char *networkId, const char *msg, unsigned int msgLen)
{
    if (networkId == NULL || msg == NULL || msgLen <= 0) {
        printf("BirefSendMessage param failed \n");
        LOG_TO_FILE("BirefSendMessage param failed");
        return -1;
    }
    printf("BirefSendMessage-------------------------------------\r\n");
    int sessionId = BirefOpenSession(networkId, TYPE_MESSAGE);
    if (sessionId < 0) {
        printf("OpenSession type message failed, sessiond [%d]\n", sessionId);
        LOG_TO_FILE("OpenSession type message failed, sessiond [%d]\n", sessionId);
        return sessionId;
    }

    int ret = SendMessage(sessionId, msg, msgLen);
    if (ret < 0) {
        printf("SendMessage type bytes failed, ret [%d]\n", ret);
        LOG_TO_FILE("SendMessage type bytes failed, ret [%d]\n", ret);
        CloseSession(sessionId);
    }
    return ret;
}

int BirefSendBytes(const char *networkId, const char *data, unsigned int dataLen)
{
    printf("******start transmission BirefSendBytes*******\n");
    if (networkId == NULL || data == NULL || dataLen <= 0) {
        printf("BirefendBytes param failed \n");
        LOG_TO_FILE("BirefendBytes param failed");
        return -1;
    }

    printf("******start transmission BirefOpenSession*******\n");
    int sessionId = BirefOpenSession(networkId, TYPE_BYTES);
    if (sessionId < 0) {
        printf("OpenSession type bytes failed, sessiond [%d]\n", sessionId);
        LOG_TO_FILE("OpenSession type bytes failed, sessiond [%d]", sessionId);
        return sessionId;
    }

    printf("******start transmission SendBytes*******\n");
    int ret = SendBytes(sessionId, data, dataLen);
    if (ret < 0) {
        printf("SendBytes type bytes failed, ret [%d]\n", ret);
        LOG_TO_FILE("SendBytes type bytes failed, ret [%d]", ret);
        CloseSession(sessionId);
    }

    printf("******start transmission SendBytes ret******* [%d]\n", ret);
    return ret;
}

int BirefSendMessageToAll(const char *msg, unsigned int msgLen)
{
    if (msg == NULL || msgLen <= 0) {
        printf("BirefSendMessageToAll param failed \n");
        LOG_TO_FILE("BirefSendMessageToAll param failed");
        return -1;
    }

    int32_t onlineNum;
    NodeBasicInfo *info = NULL;
    int ret = GetAllNodeDeviceInfo(PKG_NAME, &info, &onlineNum);
    if (ret != 0 || info == NULL) {
        printf("GetAllNodeDeviceInfo fail, ret = %d.\n", ret);
        LOG_TO_FILE("GetAllNodeDeviceInfo fail, ret = %d", ret);
        return -1;
    }
    for (int i = 0; i < onlineNum; i++) {
        ret = BirefSendMessage(info[i].networkId, msg, msgLen);
        if (ret != 0) {
            printf("send bytes failed, ret[%d]", ret);
            FreeNodeInfo(info);
            return ret;
        } 
    }
    FreeNodeInfo(info);
    return ret;
}

int BirefSendBytesToAll(const char *data, unsigned int dataLen)
{
    if (data == NULL || dataLen <= 0) {
        printf("BirefSendBytesToAll param failed \n");
        LOG_TO_FILE("BirefSendBytesToAll param failed");
        return -1;
    }

    int32_t onlineNum;
    NodeBasicInfo *info = NULL;
    int ret = GetAllNodeDeviceInfo(PKG_NAME, &info, &onlineNum);
    if (ret != 0 || info == NULL) {
        printf("GetAllNodeDeviceInfo fail, ret = %d.\n", ret);
        LOG_TO_FILE("GetAllNodeDeviceInfo fail, ret = %d", ret);
        return -1;
    }
    for (int i = 0; i < onlineNum; i++) {
        ret = BirefSendBytes(info[i].networkId, data, dataLen);
        if (ret != 0) {
            printf("send bytes failed, ret[%d]", ret);
            FreeNodeInfo(info);
            return ret;
        }
    }
    FreeNodeInfo(info);
    return ret;
}

void RegisterSessionCallback(IKHSessionCallback *callback)
{
    g_callback = callback;
}

int GetLocalDeviceId(char *deviceId, unsigned int len)
{
    if (deviceId==NULL || len<UDID_BUF_LEN) {
        printf("GetLocalDeviceId param error.\n");
        LOG_TO_FILE("GetLocalDeviceId param error.");
        return -1;
    }

    NodeBasicInfo info;
    int ret = GetLocalNodeDeviceInfo(PKG_NAME, &info);
    if (ret != 0) {
        printf("GetLocalNodeDeviceInfo fail, ret = %d.\n", ret);
        LOG_TO_FILE("GetLocalNodeDeviceInfo fail, ret = %d", ret);
        return -1;
    }

    unsigned char udid[UDID_BUF_LEN] = {0};
    ret = GetNodeKeyInfo(PKG_NAME, info.networkId, NODE_KEY_UDID, udid, UDID_BUF_LEN);
    if (ret != 0) {
        printf("GetNodeKeyInfo NODE_KEY_UDID fail, ret = %d.\n", ret);
        LOG_TO_FILE("GetNodeKeyInfo NODE_KEY_UDID fail, ret = %d", ret);
        return -1;
    }

    printf("GetNodeKeyInfo NODE_KEY_UDID  %s\n", udid);
    (void)memcpy_s(deviceId, len, udid, UDID_BUF_LEN);
    return ret;
}

int GetAllOnlineNum(unsigned int *num)
{
    if(NULL == num) {
        printf("GetAllOnlineNum param error.\n");
        LOG_TO_FILE("GetAllOnlineNum param error");
        return -1;
    }

    NodeBasicInfo *info = NULL;
    uint32_t infoNum = 0;
    int ret = LnnGetAllOnlineNodeInfo(&info, &infoNum);
    if(ret != 0){
        printf("LnnGetAllOnlineNodeInfo infoNum fail, ret = %d.\n", ret);
        LOG_TO_FILE("LnnGetAllOnlineNodeInfo infoNum fail, ret = %d", ret);
        return -1;
    }//

    if(NULL != info){
        SoftBusFree(info);
        info = NULL;
    }//

    *num = infoNum;
    return 0;
}

void BriefCloseSession(int sessionId)
{
    CloseSession(sessionId);
}
